package com.navinfo.platform.trip.common.arithmetic;

import com.navinfo.platform.trip.common.arithmetic.data.CommonData;
import com.navinfo.platform.trip.common.arithmetic.data.OuterStatisticData;
import com.navinfo.platform.trip.common.arithmetic.var.VarCommon;
import com.navinfo.platform.trip.common.arithmetic.var.VarDrivingSlope;
import com.navinfo.platform.trip.common.arithmetic.var.VarDrivingSlopeData;
import com.navinfo.platform.trip.common.arithmetic.manager.AbstractArithmetic;
import com.navinfo.platform.trip.common.config.ConfigMap;
import com.navinfo.platform.trip.common.util.ArithmeticUtils;

import java.math.BigDecimal;
import java.util.List;

/**
 * 坡路行驶算法<br/>
 * 依赖{@link Mileage}里程油耗算法<br/>
 * 赋值{@link CommonData#slope}的坡度<br/>
 * 输出：统计<br/>
 */
public class DrivingSlope extends AbstractArithmetic<VarDrivingSlope> {
    /**
     * 上坡角度最小值
     */
    private BigDecimal uphillGradMin = BigDecimal.valueOf(ConfigMap.getDouble("Uphill_Grad_Min"));
    /**
     * 上坡角度最大值
     */
    private BigDecimal uphillGradMax = BigDecimal.valueOf(ConfigMap.getDouble("Uphill_Grad_Max"));
    /**
     * 平路角度最小值
     */
    private BigDecimal levelRoadGradMin = BigDecimal.valueOf(ConfigMap.getDouble("LevelRoad_Grad_Min"));
    /**
     * 平路角度最大值
     */
    private BigDecimal levelRoadGradMax = BigDecimal.valueOf(ConfigMap.getDouble("LevelRoad_Grad_Max"));
    /**
     * 下坡角度最小值
     */
    private BigDecimal downhillGradMin = BigDecimal.valueOf(ConfigMap.getDouble("Downhill_Grad_Min"));
    /**
     * 下坡角度最大值
     */
    private BigDecimal downhillGradMax = BigDecimal.valueOf(ConfigMap.getDouble("Downhill_Grad_Max"));
    /**
     * 测量坡道距离的极限值 单位:米
     */
    private Integer gradDist = ConfigMap.getInteger("Grad_Dist");

    @Override
    public void calculate() {
        logger.debug("=============进入坡路行驶算法============");
        VarDrivingSlope varDrivingSlope = getObj();
        CommonData commonData = getCommonData();
        List<VarDrivingSlopeData> heightList = varDrivingSlope.getHeightList();

        int height = commonData.getHeight();
        double dffDistance = commonData.getDffMileage();
        logger.debug("Height:{}, dffDistance:{}", height, dffDistance);

        //加入缓存的高度和距离差中
        if (dffDistance > 0) {
            VarDrivingSlopeData slopeData = new VarDrivingSlopeData();
            slopeData.setDffDistance(dffDistance);
            slopeData.setHeight(height);
            heightList.add(slopeData);
        }

        if (heightList.size() > 0) {
            //计算首末点的高度差、距离差
            int diffHeight = heightList.get(heightList.size()-1).getHeight() - heightList.get(0).getHeight();
            double diffDistance = heightList.stream().mapToDouble(e -> e.getDffDistance()).sum();
            logger.debug("diffHeight:{},diffDistance:{}", diffHeight, diffDistance);

            //如果距离大于测量阈值计算坡度
            if (diffDistance >= gradDist) {
                //移除缓存的首点，应该就剩一个末点充当下次计算的首点
                heightList.remove(0);

                //计算坡度数据
                calcSlope(diffHeight, diffDistance);
            }
        }

        logger.debug("===============坡路行驶算法结束=============");
    }

    /**
     * 累加坡度数据
     * @param diffHeight 首末点的高度差
     * @param diffDistance 首末点的距离差
     */
    private void calcSlope(int diffHeight, double diffDistance) {
        VarDrivingSlope var = getObj();
        CommonData commonData = getCommonData();

        //计算坡度
        double slope = (Math.atan2(diffHeight, diffDistance) * 180) / Math.PI;
        BigDecimal slopeBigDecimal = BigDecimal.valueOf(slope);
        logger.debug("slope:{}", slope);

        //将坡度赋值到公共参数中
        commonData.setSlope(slope);

        int dffTime = commonData.getDffTime();
        double dffOil = commonData.getDffFuel();
        double dffDistance = commonData.getDffMileage();

        VarCommon varCommon = null;
        //上坡累加
        if (slopeBigDecimal.compareTo(uphillGradMin) >= 0 && slopeBigDecimal.compareTo(uphillGradMax) <= 0) {
            varCommon = var.getUpSlope();
        }
        //平路累加
        else if (slopeBigDecimal.compareTo(levelRoadGradMin) > 0 && slopeBigDecimal.compareTo(levelRoadGradMax) < 0) {
            varCommon = var.getLevelRoad();
        }
        //下坡累加
        else if (slopeBigDecimal.compareTo(downhillGradMin) >= 0 && slopeBigDecimal.compareTo(downhillGradMax) <= 0) {
            varCommon = var.getDownSlope();
        }

        if(null != varCommon){
            varCommon.addMileage(dffDistance);
            varCommon.addFuel(dffOil);
            varCommon.addDuration(dffTime);
        }
    }

    @Override
    public void collect(OuterStatisticData statisticDataOut) {
        VarDrivingSlope var = super.getObj();
        VarCommon upSlope = var.getUpSlope();
        statisticDataOut.setUpSlopeDrivingMileage(ArithmeticUtils.mileageMToM(upSlope.getMileage()));
        statisticDataOut.setUpSlopeDrivingFuel(ArithmeticUtils.fuelMlToMl(upSlope.getFuel()));
        statisticDataOut.setUpSlopeDrivingDuration(ArithmeticUtils.timeMsToSecond(upSlope.getDuration()));

        VarCommon levelRoad = var.getLevelRoad();
        statisticDataOut.setLevelRoadDrivingMileage(ArithmeticUtils.mileageMToM(levelRoad.getMileage()));
        statisticDataOut.setLevelRoadDrivingFuel(ArithmeticUtils.fuelMlToMl(levelRoad.getFuel()));
        statisticDataOut.setLevelRoadDrivingDuration(ArithmeticUtils.timeMsToSecond(levelRoad.getDuration()));

        VarCommon downSlope = var.getDownSlope();
        statisticDataOut.setDownSlopeDrivingMileage(ArithmeticUtils.mileageMToM(downSlope.getMileage()));
        statisticDataOut.setDownSlopeDrivingFuel(ArithmeticUtils.fuelMlToMl(downSlope.getFuel()));
        statisticDataOut.setDownSlopeDrivingDuration(ArithmeticUtils.timeMsToSecond(downSlope.getDuration()));
    }
}
